/**
 * 
 */
package org.ztest.concurrent;

import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;

/**
 * @author lhl
 *
 * 2015年10月27日 下午3:30:30
 */
public class ThreadExecutorGroup
{
	private Executor[] executors;
	
	private ExecutorChooser chooser;
	
	public ThreadExecutorGroup(ThreadFactory threadFactory, int nThreads)
	{
		executors = new SingleThreadExecutor[nThreads];
		for (int i = 0; i < nThreads; i++)
		{
			executors[i] = new SingleThreadExecutor(threadFactory);
		}
		
		if (isPowerOfTwo(nThreads))
		{
			chooser = new PowerOfTwoExecutorChooser();
		}
		else
		{
			chooser = new GenericExecutorChooser();
		}
	}
	
	public Executor next(int uid)
	{
		return chooser.next(uid);
	}
	
	public Executor next(String strUid)
	{
		return next(Objects.hashCode(strUid));
	}
	
    private static boolean isPowerOfTwo(int val)
    {
        return (val & -val) == val;
    }
	
	interface ExecutorChooser
	{
		Executor next(int uid);
	}
	
	class PowerOfTwoExecutorChooser implements ExecutorChooser
	{
		@Override
		public Executor next(int uid)
		{
			return executors[uid & (executors.length - 1)];
		}
	}
	
	class GenericExecutorChooser implements ExecutorChooser
	{
		@Override
		public Executor next(int uid)
		{
			return executors[uid % executors.length];
		}
	}
}
